package com.nexgo.payment.util;

import android.text.TextUtils;
import android.util.Log;

import com.nexgo.common.ByteUtils;
import com.nexgo.data.XMLData;
import com.nexgo.data.entity.RecvData;
import com.nexgo.data.entity.SendData;
import com.nexgo.data.json.JsonRecData;
import com.nexgo.data.json.JsonSendData;
import com.nexgo.data.json.JsonTools;
import com.nexgo.data.json.bean.JsonBody;
import com.nexgo.oaf.apiv3.device.pinpad.CalcModeEnum;
import com.nexgo.oaf.apiv3.device.pinpad.DesKeyModeEnum;
import com.nexgo.oaf.apiv3.device.pinpad.MacAlgorithmModeEnum;
import com.nexgo.oaf.apiv3.device.pinpad.PinPad;
import com.nexgo.oaf.apiv3.device.pinpad.WorkKeyTypeEnum;
import com.nexgo.payment.App;
import com.nexgo.payment.R;
import com.nexgo.payment.api.ApiDeviceEngine;
import com.nexgo.payment.constrant.ResponseState;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmlpull.v1.XmlPullParserException;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;

/**
 * Created by xiaox on 2017/2/3.
 */

public class MessageHelper {
    private static final Logger mLog = LoggerFactory.getLogger(MessageHelper.class.getSimpleName());

    /**
     * 组报文头
     *
     * @param tpdu
     * @return
     */
    public static String formMessageHeader(String tpdu) {
        StringBuilder sb = new StringBuilder();
//        sb.append(tpdu);
//        wzp delete 交行没有
/*        sb.append("61");
        sb.append(BuildConfig.APP_MASTER_VERSION);
        sb.append("00");
        sb.append(BuildConfig.APP_BRANCH_VERSION);*/
        return sb.toString();
    }

    /**
     * 检查接收包与发送包信息是否一致
     *
     * @param send    发送包
     * @param receive 接收包
     * @return
     */
    public static boolean AlidityOfReceive(SendData send, RecvData receive) {
        String sendMsgType = send.getMsgType();
        String recvMsgType = receive.getMsgType();
        if (TextUtils.isEmpty(recvMsgType)) {
            return false;
        }
        if (Integer.parseInt(sendMsgType) + 10 != Integer.parseInt(recvMsgType)) {
            return false;
        }
        if (!TextUtils.isEmpty(send.getTraceNum()) && !TextUtils.isEmpty(receive.getTraceNum())) {
            if (!send.getTraceNum().equals(receive.getTraceNum())) return false;
        }
        if (!TextUtils.isEmpty(send.getProcCode())) {
            if (!send.getProcCode().equals(receive.getProcCode())) return false;
        }
        if (!TextUtils.isEmpty(send.getAmount()) && !TextUtils.isEmpty(receive.getAmount())) {
            if (!send.getAmount().equals(receive.getAmount())) return false;
        }
        if (!TextUtils.isEmpty(send.getTerminalId()) && !TextUtils.isEmpty(receive.getTerminalId())) {
            if (!send.getTerminalId().equals(receive.getTerminalId())) return false;
        }
        if (!TextUtils.isEmpty(send.getMerchantId()) && !TextUtils.isEmpty(receive.getMerchantId())) {
            if (!send.getMerchantId().equals(receive.getMerchantId())) return false;
        }
/*        //结算报文没有
        if (!sendMsgType.startsWith("05")) {
            String respCode = receive.getRespCode().trim();
            String regex = "^(A|a|[0-9])[0-9]$";
            //判断响应码格式是否正确
            if (TextUtils.isEmpty(respCode) || !RegexUtils.isMatch(regex, respCode)) {
                return false;
            }
        }*/
        return true;
    }

    /**
     * 判断交易响应码是否成功
     *
     * @param responseCode
     * @return
     */
    public static boolean isSuccessful(String responseCode) {
        return "00".equalsIgnoreCase(responseCode);
    /*            || "11".equalsIgnoreCase(responseCode)
                || "A2".equalsIgnoreCase(responseCode)
                || "A4".equalsIgnoreCase(responseCode)
                || "A5".equalsIgnoreCase(responseCode)
                || "A6".equalsIgnoreCase(responseCode);*/
    }
    /**
     * 判断交易响应码是否成功
     *
     * @param responseCode
     * @return
     */
    public static boolean isSettleSuccessful(String responseCode) {
        return "00".equalsIgnoreCase(responseCode)
                || "95".equalsIgnoreCase(responseCode); //结算
    /*            || "11".equalsIgnoreCase(responseCode)
                || "A2".equalsIgnoreCase(responseCode)
                || "A4".equalsIgnoreCase(responseCode)
                || "A5".equalsIgnoreCase(responseCode)
                || "A6".equalsIgnoreCase(responseCode);*/
    }

    public static boolean isScanSuccessful(String responseCode) {
        return "00".equalsIgnoreCase(responseCode)
                || "ww".equalsIgnoreCase(responseCode); //联机退货
    /*            || "11".equalsIgnoreCase(responseCode)
                || "A2".equalsIgnoreCase(responseCode)
                || "A4".equalsIgnoreCase(responseCode)
                || "A5".equalsIgnoreCase(responseCode)
                || "A6".equalsIgnoreCase(responseCode);*/
    }
    /**
     * wzp 判断扫码交易响应码是否成功
     *
     * @param  field48
     * @return
     */
    public static int isScanfield48Successful(String field48 ,boolean isQuery) {
        int result = -1;
        try {
            XMLData xmlData = XmlUtils.Parser(field48);
            String respond = xmlData.getResp_code();
            if(respond != null){
                mLog.debug("respond :{}",respond);
                if("N".equals(respond)){  //交易成功
                    result = 1 ; //交易直接返成功
                    if(isQuery){
                        respond = xmlData.getTxn_state();
                        switch (Integer.parseInt(respond)){
                            case 1:
                            case 2:
                                result = 0 ; //查询
                                break;
                            case 6:
                                result = 1 ; //查询成功
                                break;
                            default:
                                break;
                        }
                    }
                }else if("S".equals(respond)){
                    result = 0;
                }
            }
        } catch (IOException | XmlPullParserException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 判断冲正响应码是否成功
     *
     * @param responseCode
     * @return
     */
    public static boolean isReversalSuccessful(String responseCode) {
        return "00".equalsIgnoreCase(responseCode)
                || "12".equalsIgnoreCase(responseCode)
                || "25".equalsIgnoreCase(responseCode);
    }

    /**
     * 判断联机退货响应码是否成功
     *
     * @param responseCode
     * @return
     */
    public static boolean isOnlineRefundSuccessful(String responseCode) {
        return "00".equalsIgnoreCase(responseCode)
                || "T1".equalsIgnoreCase(responseCode);
    }

    /**
     * 根据响应码获取响应描述
     *
     * @param responseCode 响应码
     * @return 返回响应描述
     */
    public static String getResponseCodeErrorInfo(String responseCode) {
        try {
            Properties properties = new Properties();
            InputStream inputStream = MessageHelper.class.getResourceAsStream("/assets/response_code.properties");
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"GBK"));
            properties.load(bufferedReader);
            return properties.getProperty(responseCode);
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 根据扫码响应码获取响应描述
     *
     * @param scan_state 响应码
     * @return 返回响应描述
     */
    public static String getScanStateCodeErrorInfo(String scan_state) {
        try {
            Properties properties = new Properties();
            InputStream inputStream = MessageHelper.class.getResourceAsStream("/assets/scan_state.properties");
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"GBK"));
            properties.load(bufferedReader);
            //lr add
            if(properties.getProperty(scan_state) == null){
                return App.sContext.getString(R.string.trans_unknow);
            }
            return properties.getProperty(scan_state);
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 根据银行代码获取银行名称
     *
     * @param bankCode 银行代码
     * @return 返回银行名称
     */
    public static String getBankName(String bankCode) {
        try {
            if (TextUtils.isEmpty(bankCode)) return null;
            Properties properties = new Properties();
            InputStream inputStream = MessageHelper.class.getResourceAsStream("/assets/bank_code.properties");
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            properties.load(bufferedReader);
            String bankName = properties.getProperty(bankCode);
            if (!TextUtils.isEmpty(bankName)) {
                return bankName.split("|")[0];
            }
            return bankCode;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    public static String getBankNameShort(String bankCode) {
        try {
            if (TextUtils.isEmpty(bankCode)) return null;
            Properties properties = new Properties();
            InputStream inputStream = MessageHelper.class.getResourceAsStream("/assets/bank_code.properties");
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            properties.load(bufferedReader);
            String bankName = properties.getProperty(bankCode);
            if (!TextUtils.isEmpty(bankName)) {
                return bankName.split("|")[1];
            }
            return bankCode;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 磁道数据加密
     *
     * @param track   磁道数据
     * @param mKeyIdx 密钥索引
     * @return 返回加密后的数据
     */
    public static String trackEncrypt(String track, int mKeyIdx) {
        byte[] trackEncrypt;
        int len ;

        byte[] needEncryptData = new byte[8];
        PinPad sdkPinPad = ApiDeviceEngine.getInstance().getPinPad();
        trackEncrypt = ByteUtils.string2ASCIIByteArray(track);
        if( track.length() < 48)
            len = 48;
        else
            len = 112;

        mLog.debug("trackEncrypt.length {} track {}",track.length(),track);
        byte[] tmpEncryptData = new byte[len];
        byte[] desResult = new byte[len];
        System.arraycopy(ByteUtils.int2BCDByteArray(track.length()), 0, tmpEncryptData, 0, 2);
        System.arraycopy(trackEncrypt, 0, tmpEncryptData, 2, trackEncrypt.length);
        Log.d("wzp", "trackEncrypt: 磁道数据加密前 {}"+ ByteUtils.byteArray2HexString(tmpEncryptData));
        byte[] result ;
        for(int i = 0; i < len / 8 ; i++){
            System.arraycopy(tmpEncryptData, i * 8, needEncryptData, 0, 8);
            result = sdkPinPad.calcByWKey(mKeyIdx, WorkKeyTypeEnum.TDKEY, needEncryptData, needEncryptData.length, CalcModeEnum.ENCRYPT);
//                result = sdkPinPad.encryptTrackData(mKeyIdx, needEncryptData, 8);
            if (result == null ) {
                mLog.debug(" trackEncrypt  == null ");
                return null;
            }
            else{
                mLog.debug(" trackData  trackData {} ",ByteUtils.byteArray2HexString(result));
                System.arraycopy( result , 0, desResult, i*8, 8);
            }
        }
        return ByteUtils.byteArray2HexString(desResult);
    }

    /**
     * 计算MAC校验值
     *
     * @param data    计算数据
     * @param mKeyIdx 密钥索引
     * @return 返回计算后的值
     */
    public static byte[] calcMac(byte[] data, int mKeyIdx) {
        PinPad sdkPinPad = ApiDeviceEngine.getInstance().getPinPad();

        mLog.debug("calcMac lenth  {} :  calcMac {}",data.length, ByteUtils.byteArray2HexString(data) );
//        wzp modify
        if( data.length > 512 ){
            byte [] calcData = new byte[512];
            System.arraycopy(data,0,calcData,0,512);
            byte[] bytes = sdkPinPad.calcMac(mKeyIdx, MacAlgorithmModeEnum.X919, DesKeyModeEnum.KEY_ALL, calcData);
            mLog.debug("OnCalcMacListener calcMac1 = {}",bytes);
            return bytes;
        }else{
            byte[] bytes = sdkPinPad.calcMac(mKeyIdx, MacAlgorithmModeEnum.X919, DesKeyModeEnum.KEY_ALL, data);
            mLog.debug("OnCalcMacListener calcMac2 = {}",bytes);
            return bytes;
        }

//        return sdkPinPad.calcMac(mKeyIdx, MacAlgorithmModeEnum.ECB, data);
    }

    //lr add
    public static String Decrypt(int algorithmID, String appID, String branchID, String index, String data) {
        if( data.length() > 0 ){
            try {
                //xhj add
//                return UnionApi.getInstance().DecryptData(algorithmID,appID,branchID,index,data);
                return ByteUtil.CalcByWKey(data,true);
            } catch (Exception e) {
                mLog.debug("解密失败");
                e.printStackTrace();
                return null;
            }
        }else{
            return null;
        }
    }

    /**
     * 计算sign
     *
     * @param data    计算数据
     * @param mKeyIdx 密钥索引
     * @return 返回计算后的值
     */
    public static String calcSign(JsonSendData data, int mKeyIdx) {
        PinPad sdkPinPad = ApiDeviceEngine.getInstance().getPinPad();

        //拼接数据 key字母顺序 key1=value1&key2+value...
//        String str = "REQ_BODY"+ "=" + data.getREQ_BODY() + "&" + "REQ_HEAD" + "=" +data.getREQ_HEAD();

        TreeMap<String, String> treeMap = new TreeMap<>();
        //取head数据
        Field[] fields = data.getREQ_HEAD().getClass().getDeclaredFields();
        Object value;
        for (Field f : fields) {
            f.setAccessible(true);
            try {
                value = f.get(data.getREQ_HEAD());
                treeMap.put(f.getName(),(String)value);
                mLog.debug("key = {} value = {}",f.getName(),value);
            } catch (IllegalAccessException e) {
                mLog.debug("取数据失败");
                e.printStackTrace();
            }
        }
        //取body数据
        JsonBody jsonBody = JsonTools.fromJson(data.getREQ_BODY().getDECRYPT(),JsonBody.class);
        Field[] fields1 = jsonBody.getClass().getDeclaredFields();
        Object value1;
        for (Field f : fields1) {
            f.setAccessible(true);
            try {
                value1 = f.get(jsonBody);
                if(f.getName().equals("_$8583data")){
                    treeMap.put(f.getName().substring(2,f.getName().length()),(String) value1);
                }else {
                    treeMap.put(f.getName(), (String) value1);
                }
                mLog.debug("key = {} value = {}",f.getName(),value1);
            } catch (IllegalAccessException e) {
                mLog.debug("取数据失败");
                e.printStackTrace();
            }
        }
        StringBuilder signData = new StringBuilder();
        for (Map.Entry<String, String> s : treeMap.entrySet()) {
            String k = s.getKey();
            String v = s.getValue();
            if (v == null ||v.equals("")||k.equals("sign")) {// 过滤空值
                continue;
            }
            signData.append(k).append("=").append(v).append("&");
        }
        mLog.debug("signData = {}",signData);

        String str = signData.toString();

        String sha256 =EncryptUtils.encryptSHA256ToString(str.substring(0,str.length()-1));
        mLog.debug("sha256 = {}",sha256);

        String s = ByteUtils.byteArray2HexString(sdkPinPad.calcMac(mKeyIdx, MacAlgorithmModeEnum.X919, DesKeyModeEnum.KEY_ALL, ByteUtils.hexString2ByteArray(sha256)));
        mLog.debug("OnCalcSignListener = {}",s);
        return s;
    }

    /**
     * 校验接收包信息
     *
     * @param sendData 发送包
     * @param recvData 接收包
     * @return {@link ResponseState}
     */
    public static ResponseState checkResponse(SendData sendData, RecvData recvData, int mKeyIdx) {
        //判断接收包是否缺少域
        boolean isAlidity = AlidityOfReceive(sendData, recvData);
        if (!isAlidity) {
            mLog.debug("域校验错");
            return ResponseState.ERR_FIELD;
        }
        //校验mac 签到不校验 后台会返回
       /* if (!sendData.getProcCode().startsWith("91")) {
            if (!TextUtils.isEmpty(recvData.getMac())) {
                byte[] str = recvData.getOperateData();
                //test
                *//*String str1 = "0210703c00800ac0060519621214200000000001203000003018008317660000301224380330291200414135353535313338313038303035354141353535353330313134303835383132303030310026433030303030303030303030304330303138303130303535303500369f36020976910a086d2d3c7175210b30307211860f04da9f790a00000005200053fc58f70012303030303031303030303330";
                mLog.debug("返回测试MAC值：{}", ByteUtils.byteArray2HexString(calcMac(str1.getBytes(),mKeyIdx)));*//*
                //end
                mLog.debug("getOperateData：{} ", ByteUtils.byteArray2HexString(str));
                byte[] calcMac = calcMac(recvData.getOperateData(), mKeyIdx);
                mLog.debug("返回MAC值：{},计算值：{}", recvData.getMac(), ByteUtils.byteArray2HexString(calcMac));
                //mac错
                if (!Arrays.equals(calcMac, ByteUtils.hexString2ByteArray(recvData.getMac()))) {
                    mLog.debug("校验后台mac错");
                    return ResponseState.ERR_MAC;
                }
            }
        }*/
        //响应码是不是成功，如果无响应码，判断域的时候就会报错了，除非是结算报文
        if (!TextUtils.isEmpty(recvData.getRespCode())) {
            boolean isSuccessfullyTrans = false;
            String sendMsgType = sendData.getMsgType();
            //判断是否是冲正交易
            if (sendMsgType.startsWith("04")){
                isSuccessfullyTrans = isReversalSuccessful(recvData.getRespCode());
            }else if(sendMsgType.equals("0220") && sendData.getProcCode().equals("200000") && sendData.getConditionCode().equals("60")) {
                isSuccessfullyTrans = isOnlineRefundSuccessful(recvData.getRespCode());
            } else if(sendMsgType.equals("0820") && sendData.getProcCode().equals("920000") && sendData.getConditionCode().equals("00")) {
                isSuccessfullyTrans = isSettleSuccessful(recvData.getRespCode());
            }else {
                isSuccessfullyTrans = isSuccessful(recvData.getRespCode());
            }
            if (!isSuccessfullyTrans) return ResponseState.ERR_RESPONSE;
        }
        return ResponseState.SUCCESS;
    }
	 //校验扫码
    public static ResponseState checkScanResponse(JsonSendData sendData, JsonRecData recvData, int mKeyIdx, boolean isQuery){
        int result = -1;

        if("N".equals(recvData.getREQ_BODY().getResponseType())){  //交易成功
            result = 1;
            if(isQuery){
                JsonBody jsonBody = JsonTools.fromJson( recvData.getREQ_BODY().getDECRYPT(),JsonBody.class);
                String respond = jsonBody.getTxn_state();
                switch (Integer.parseInt(respond)){
                    case 1:
                    case 2:
                        result = 0 ; //查询
                        break;
                    case 6:
                        result = 1 ; //查询成功
                        break;
                    default:
                        result = -2; //查询其他状态原交易没有支付成功
                        break;
                }
            }
        }else if("S".equals(recvData.getREQ_BODY().getResponseType())){
            result = 0;
        }else if("E".equals(recvData.getREQ_BODY().getResponseType())){
            result = -3;
        }

        if ( result == 0){
            return ResponseState.ERR_SCAN;
        }else if( result == -1){
            return ResponseState.ERR_FIELD48;
        }else if(result == -2){
            return ResponseState.ERR_MESSAGE;
        }else if(result == -3){
            return ResponseState.ERR_FAIL;
        }

        return ResponseState.SUCCESS;
    }
}
